package service

import (
	"fmt"
	"path/filepath"
	"strings"
)

const (
	chkInterval = 5
)

type Service struct {
	// 服务名称
	SrvName string
	// 服务版本号
	SrvVerion string
	// 服务安装路径
	WorkDir string
	// 服务类型
	SrvLang string
	// 服务进程文件
	PidFile string
	//服务启动参数
	SrvOption string
	//服务描述
	Description string
	//服务启动命令
	RunCmd string
	// 启动超时时间
	StartTimeout int
	// 健康检查url
	HealthUrl string
	// 配置文件路径
	Config string
	// 备份
	Backup backup
	// 服务来源
	Source src
}

type backup struct {
	// 备份文件目录
	Dir string
	// 备份文件后缀
	Postfix string
}

type src struct {
	// 源文件目录
	Dir string
	// 包文件名称
	Name string
	// 包来源
	From string
	// 下载路径
	Url string
	// 配置文件目录
	Config string
}

type SrvAction interface {
	SrvName() string
	// 启动
	Start() error
	// 停止
	Stop() error
	// 重启
	Restart() error
	// 状态
	Status() bool
	// 部署
	Deploy() error
	// 卸载
	Uninstall() error
	// 回滚
	Rollback(updateConfig bool) error
	// 更新
	Update(updateConfig bool) error
	// 命令是否存在
	GetCmd() (string, error)
	// 描述服务信息
	Describ() string
}

func (s Service) Action() SrvAction {
	var srv SrvAction
	switch s.SrvLang {
	case "java":
		srv = &javaService{
			srvName:      s.SrvName,
			srvLang:      s.SrvLang,
			cmdArgs:      s.SrvOption,
			pkgName:      s.Source.Name,
			workDir:      s.WorkDir,
			backupDir:    s.Backup.Dir,
			pkgSourceDir: s.Source.Dir,
			srcConfigDir: s.Source.Config,
			configDir:    s.Config,
			bakPostfix:   s.Backup.Postfix,
			healthUrl:    s.HealthUrl,
			runCmd:       s.RunCmd,
			startTimeout: s.StartTimeout,
			pidFile:      s.PidFile,
			pkgPostfix:   s.postfix(),
			pkgFrom:      s.Source.From,
			pkgUrl:       s.Source.Url,
			description:  s.Description,
		}
	case "html":
		srv = &htmlService{
			srvName:      s.SrvName,
			srvLang:      s.SrvLang,
			cmdArgs:      s.SrvOption,
			pkgName:      s.Source.Name,
			workDir:      s.WorkDir,
			backupDir:    s.Backup.Dir,
			pkgSourceDir: s.Source.Dir,
			srcConfigDir: s.Source.Config,
			configDir:    s.Config,
			bakPostfix:   s.Backup.Postfix,
			healthUrl:    s.HealthUrl,
			runCmd:       s.RunCmd,
			startTimeout: s.StartTimeout,
			pidFile:      s.PidFile,
			pkgPostfix:   s.postfix(),
			pkgFrom:      s.Source.From,
			pkgUrl:       s.Source.Url,
			description:  s.Description,
		}
	case "docker":
		srv = &dockerService{
			srvName:      s.SrvName,
			srvLang:      s.SrvLang,
			cmdArgs:      s.SrvOption,
			pkgName:      s.Source.Name,
			workDir:      s.WorkDir,
			backupDir:    s.Backup.Dir,
			pkgSourceDir: s.Source.Dir,
			srcConfigDir: s.Source.Config,
			configDir:    s.Config,
			bakPostfix:   s.Backup.Postfix,
			healthUrl:    s.HealthUrl,
			runCmd:       s.RunCmd,
			startTimeout: s.StartTimeout,
			pidFile:      s.PidFile,
			pkgPostfix:   s.postfix(),
			pkgFrom:      s.Source.From,
			pkgUrl:       s.Source.Url,
			description:  s.Description,
		}
	default:
		fmt.Printf("当前程序还未支持%s类型的程序，敬请期待\n", s.SrvLang)
		srv = &defaultService{
			srvName:      s.SrvName,
			srvLang:      s.SrvLang,
			cmdArgs:      s.SrvOption,
			pkgName:      s.Source.Name,
			workDir:      s.WorkDir,
			backupDir:    s.Backup.Dir,
			pkgSourceDir: s.Source.Dir,
			srcConfigDir: s.Source.Config,
			configDir:    s.Config,
			bakPostfix:   s.Backup.Postfix,
			healthUrl:    s.HealthUrl,
			runCmd:       s.RunCmd,
			startTimeout: s.StartTimeout,
			pidFile:      s.PidFile,
			pkgPostfix:   s.postfix(),
			pkgFrom:      s.Source.From,
			pkgUrl:       s.Source.Url,
			description:  s.Description,
		}
	}
	return srv
}

func (s Service) postfix() string {
	postFix := filepath.Ext(s.Source.Name)
	return postFix
}

type ServiceError struct {
	Name    string
	ErrDesc []string
}

func (s *ServiceError) Error() string {
	return fmt.Sprintf("服务%s %s", s.Name, strings.Join(s.ErrDesc, " "))
}

func NewServiceError(name string, errDesc ...string) *ServiceError {
	return &ServiceError{
		Name:    name,
		ErrDesc: errDesc,
	}
}
